/* Duo frame by Goog、2022 */

class Duo {
    constructor(_app) {
        for (let _key in _app) {
            this[_key] = _app[_key];
        }
    }
    /* 虚拟DOM树 */
    DuoVDOMTree = [];
    /* 虚拟代码碎片 */
    DuoVDOMFragments = [];
    /* 事件托管存储器 */
    DuoEvents =[];
    /* 事件类型监听器 要被监听的事件存储在这 */
    DuoListeners = [];
    createDuo() {
        if (this.entry) { 
            this.template = !this.template?controlDOMVal(this.entry):this.template;
         }
        if (this.template) {
            this.DuoVDOMTree = createDuoVDOMTree(this.template);
        } else {
            this.thowError('创建VDOM失败!您的模板代码不正确!');
        }
        return this;
    }
    /* 创建虚拟DOM代码片段 */
    createDuoFragments() {
        this.DuoVDOMFragments = this.renderVDOMtoDuoFragments(this.DuoVDOMTree);
        return this;
    }
    /* 渲染虚拟DOM */
    renderVDOMtoDuoFragments(_DuoVDOMTree) {
        let tempDuoVDOMFragments = document.createDocumentFragment();
        _DuoVDOMTree.forEach(_itemDOM=>{
           
            const {__index,__strInfos,__tagInfos,__tagChildren} = _itemDOM;
            
            if(__tagInfos){
                const {__value,__tagName,__innerHtml,__attributes} = __tagInfos;
                let tempDOM = document.createElement(__tagName)
                if(__attributes){
                    /* 添加属性 */
                    __attributes.forEach(_item=>{
                        const {__attrKey,__attrVal} = _item;
                        if(/\$[a-z]+/gi.test(__attrKey)){
                            /* 使用了Duo框架的事件绑定语法的key */
                            tempDOM.setAttribute(this.regEvent(__attrKey,__attrVal),'')
                        }else if(__attrKey==='class'){
                            let classVals =  replaceDoubleSpace(__attrVal.trim())
                            classVals.split(" ").forEach(_itemClassName=>{
                                tempDOM.classList.add(_itemClassName)
                            })
                            
                        }else{
                            tempDOM[__attrKey] = __attrVal;
                        }
                        
                    })
                    //regEvent(_eventKey,_eventVal)
                }
                if(!__tagChildren){
                    /* 赋予innerHTML属性 */
                    tempDOM.innerHTML = this.getData(__innerHtml);
                }else {
                    tempDOM.appendChild(this.renderVDOMtoDuoFragments(__tagChildren))
                }
                tempDuoVDOMFragments.appendChild(tempDOM)
            }else if(__strInfos){
                let tempDOM = document.createTextNode(this.getData(__strInfos))
                tempDuoVDOMFragments.appendChild(tempDOM)
            }
            
        
        })
        return tempDuoVDOMFragments;
    }
    /* 事件绑定解析 */
    /* data解析 */
    getData(__innerHtml){
        let finallyHtml = __innerHtml;
        if(/\[\[.+\]\]/.test(__innerHtml)){
            __innerHtml.match(/\[\[[^\]\[]+\]\]/gi)?.forEach(_item=>{
                let originalCode = _item.replace('[[','').replace(']]','');
                finallyHtml=  finallyHtml.replace(_item,this.data[originalCode])
            })       
        }
        return finallyHtml;
    }
    /* 渲染真实DOM */
    renderDOM(_entry) {
        this.entry = _entry;
        this.createDuo();
        this.createDuoFragments();
        if(this.entry){
            getDOM(this.entry).innerHTML=null;
            getDOM(this.entry).appendChild(this.DuoVDOMFragments);
        }
        /* 监听事件 */
        this.DuoListeners&&this.onListeners();
        this.welcomeMsg('欢迎使用铎哥框架 Version 0.1.220503.beta!')
        return this;
  
    }
    /* 听众事件监听 */
    onListeners(){
        this.DuoListeners.forEach(_eventName=>{
            let that = this;
            getDOM(that.entry).addEventListener(_eventName,(e)=>{
                let stars = that.DuoEvents.filter(_item=>{
                    return _item['eventName'] === _eventName;
                })
                for(let i=0;i<stars.length;i++){
                    if(e.target.getAttribute(stars[i]['eventKey'])==''){
                        let tempFn = that['fs'][stars[i]['eventCallback']]; 
                        if(that['fs']&&tempFn){
                            /* 把fs的this指向duo */
                            that['fs']&&tempFn.call(that);
                        }
                    }
                }
            })
        })
    }
    /* 注册事件听众 */
    regListeners(_eventName){
        (!this.DuoListeners.includes(_eventName))?this.DuoListeners.push(_eventName):void(0);
    }
    /* 处理绑定的事件 */
    regEvent(_eventKey,_eventVal){
        let eventKey = getRandomEventKey();
        if(/\$[a-z]+/g.test(_eventKey)){       
            if(isIncludes(this.DuoEvents,'eventKey',eventKey)){
                this.regEvent(_eventKey,_eventVal); // 如果这个key存在就重新开始
            }
            /* 添加事件听众 */
            this.regListeners(_eventKey.slice(1))
            /* 保存到事件 */
            this.DuoEvents.push({
                eventName:_eventKey.slice(1),
                eventKey,
                eventCallback:_eventVal
            })
        }
        return eventKey; // 返回注册了的key
    }
    /* 抛出错误 */
    thowError(_str) {
        throw Error(`[An Error From DUO Frame!]:${_str}`)
    }
    /* 警告 */
    thowWarn(_str) {
        console.warn(`[A Warning From DUO Frame!]:${_str}`)
    }
    /* 铎哥框架提示 */
    welcomeMsg(_str){
        console.info('%c'+`Duo.js:${_str}`,'display:inline-block;background-color:pink;color:white;padding:2px;font-size:14px;border:2px solid #eee;border-radius: 15px;font-weight:700;text-shadow:1px 1px 10px rgba(0,0,0,.3);')
    }

}
/* 虚拟DOM操作 */


/* 真实DOM操作 获取DOM */
function getDOM(_domSymbol,_entry=document){
    let reusltDOM = {}
    if (_entry) {
        reusltDOM = _entry.querySelector(_domSymbol);
    } else {
        reusltDOM = document.querySelector(_domSymbol);
    }
    return reusltDOM
}
/* 真实DOM操作 获取或者设置value*/
function controlDOMVal(_domSymbol,_entry=document, _newVal = null) { // 获取DOM的value值如果不存在就获取innerHTML值
    let reusltDOM = getDOM(_domSymbol,_entry,);
    _newVal ? reusltDOM['value'] ? reusltDOM['value'] = _newVal : reusltDOM['innerHTML'] = _newVal : void (0);
    return reusltDOM['value'] ? reusltDOM['value'] : reusltDOM['innerHTML'];
}

/* 创建DuoVDOM */
function createDuoVDOMTree(_DOMStr) {
    let tempDuoTags = (new DuoTags(_DOMStr)).tagsEach();
    let tempDuoVDOMTreeArr = [];
    tempDuoTags.forEach((_item, _index) => {
        if (/<.+>|<\/.+>/.test(_item)) {
            let __tagInfos = handleTag(_item);
            let __tagChildren = __tagInfos.__innerIncludeTag ? createDuoVDOMTree(__tagInfos.__innerHtml) : null;
            tempDuoVDOMTreeArr.push({ _index, __tagInfos, __tagChildren })
        } else {
            tempDuoVDOMTreeArr.push({ _index, __strInfos: _item })
        }

    })
    return tempDuoVDOMTreeArr;
}

/** 
 *  匹配标签
 *  match tags
 * */

class DuoTags {
    constructor(_template) {
        this.template = _template; // 标签字符串模板
    }

    /* 2.初始化一些参数 */
    templateArr = [];
    tempStr = ''; // 临时匹配的字符串
    resultArr = []; // 最终返回的标签数组
    matchTagStartTimes = 0; // 标签头个数
    matchTagEndTimes = 0; // 标签尾个数
    tagName = '';
    matchMode = 0; // 匹配字符串文本模式
    /* 3.遍历字符串 */
    tagsEach = () => {
        /* 0.丢弃注释 */
        this.template = this.template.replace(/\<\!\-\-.*\-\-\>/gi, '');
        /* 1.分割文本为单个字符 */
        this.templateArr = this.template.split('');
        this.templateArr.forEach(_itemStr => {
            this.tempStr += _itemStr;
            switch (this.matchMode) {
                case 0: this.handleMatchString(_itemStr); break;
                case 1: this.handleMatchTagName(_itemStr); break;
                case 2: this.handleMatchTagHeader(_itemStr); break;
                case 3: this.handleMatchTagContent(); break;
            }
        })
        this.templateArr = null;
        return this.resultArr;
    }

    /* 清空临时存储字符变量 */
    clearStr = () => {
        this.tempStr = '';
    }

    /* 0.处理匹配字符串 */
    handleMatchString = (_str) => {
        if (_str === '<') {
            if (this.tempStr.length > 1) {
                this.resultArr.push(this.tempStr.slice(0, -1)); // 把字符串加入返回数组里面
            }
            this.clearStr(); // 清空临时文本 
            this.matchMode = 1; // 打开匹配标签名模式
        }
    }

    /* 1.匹配标签名模式 */
    handleMatchTagName = (_str) => {
        if (/\s|[>]|[\/]/.test(_str)) {
            this.tagName = this.tempStr.slice(0, -1); // 存储标签名
            if (_str === '>') {
                this.matchMode = 3; // 打开匹配标签内容模式
            } else if (/\/>/.test(this.tempStr)) {
                this.resultArr.push('<' + this.tempStr); // 把字符串加入返回数组里面
                this.clearStr(); // 清空临时文本
                this.matchMode = 0; // 匹配字符串模式
            } else {
                this.matchMode = 2; // 打开匹配标签头模式
            }
        }
    }

    /* 2.配标签头模式 */
    handleMatchTagHeader = (_str) => {
        if (/\/>/.test(this.tempStr)) {
            this.resultArr.push('<' + this.tempStr); // 把字符串加入返回数组里面
            this.clearStr(); // 清空临时文本
            this.matchMode = 0; // 匹配字符串模式
        } else if (_str === '>') {
            this.matchMode = 3; // 打开匹配标签内容模式
        }
    }

    /* 3.匹配标签内容模式 */
    handleMatchTagContent = (_str) => {
        let regExpTagHeader = new RegExp(`<${this.tagName}.*>`, 'gi');
        let regExpTagFooter = new RegExp(`</${this.tagName}>`, 'gi');
        if (regExpTagFooter.test(this.tempStr)) {
            this.matchTagStartTimes = this.tempStr.match(regExpTagHeader) && this.tempStr.match(regExpTagHeader).length || 0;
            this.matchTagEndTimes = this.tempStr.match(regExpTagFooter).length;
            if (this.matchTagEndTimes - this.matchTagStartTimes === 1) {
                this.resultArr.push('<' + this.tempStr); // 把字符串加入返回数组里面
                this.matchMode = 0; // 匹配字符串模式
                this.clearStr(); // 清空临时文本
            }
        }
    }
}

/**
 *  获取标签信息
 */

/* Obtaining Label Information */
function handleTag(_eleStr = '') {

    let tempTagName = '';
    let tempStrArr = _eleStr.split("");
    for (let i = 1; i < tempStrArr.length; i++) {
        if (tempStrArr[i] == '>' || tempStrArr[i] == ' ') {
            break;
        } else {
            tempTagName += tempStrArr[i]
        }
    }

    /* Is it a self-closing tag ? */
    let endStr = _eleStr.substring(_eleStr.length - (tempTagName.length + 3))
    let tempInnerHTML = null;
    if (endStr === `</${tempTagName}>`) { // 检测是不是闭合标签
        tempInnerHTML = _eleStr.substring(_eleStr.indexOf('>') + 1, _eleStr.length - endStr.length);
    }

    /* Get all Attributes */
    let attributesAreaStr = _eleStr.substring(`<${tempTagName}`.length, _eleStr.indexOf('>')).trim();
    let attributesArrEntry = [];
    let attributesArrOutput = [];
    let resultValue = null;
    if (attributesAreaStr.length !== 0) {
        attributesArrEntry = replaceDoubleSpace(attributesAreaStr).split(" ");
        attributesArrEntry.forEach(_item => {
            let tempKey = null;
            let tempValue = null;
            if (_item !== '/') {
                if (_item.indexOf("=\"") !== -1) {
                    let tempArr = _item.split("=\"");
                    tempKey = tempArr[0];
                    tempValue = tempArr[1].slice(0, -1);
                    tempKey === 'value' ? resultValue = tempValue : null;
                } else {
                    tempKey = _item
                }
                attributesArrOutput.push({
                    __attrKey: tempKey,
                    __attrVal: tempValue
                })
            }
        });
    }
    return {
        __value: resultValue,
        __innerHtml: tempInnerHTML,
        __tagName: tempTagName,
        __innerIncludeTag: tempInnerHTML ? tempInnerHTML.search(/[<].*[>]/) !== -1 : null,
        __attributes: attributesArrOutput
    }
}

/* Replace two Spaces with one */
function replaceDoubleSpace(_str = '') {
    let resultStr = _str.replace('  ', ' ')
    return resultStr.search('  ') === -1 ? resultStr : replaceDoubleSpace(resultStr);
}


/* 生成绑定事件随机key */
function getRandomEventKey(){
    let tempString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let tempArr = tempString.split("");
    let max = tempString.length;
    let num = 10;
    let result = '';
    for(let i=0;i<num;i++){
        result += tempArr[getRandom(0, max)];
    }
    return `Duo-Event-${result}`;
}

 
// 随机数函数 
function getRandom(min,max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
} 

/* 判断一个数组里面指定的key包含value */
function isIncludes(_arr=[],_key,_value){
    let finnal = false; // 状态守卫 state guard
    for(let i=0;i<_arr.length;i++){
        if(_arr[i][_key]===_value){
            finnal = true;
            break;
        }
    }
    return finnal;
}

/* 使用 */

/* 创建一个Duo实例 */
function createDuo(_app) {
    return new Duo(_app)
}
/* 获得当前实例 */
function getSelf() {

}